;int cargar arbol huffman ( codigo t *tabla codigos, nodo arbol t **a )
; • Descripción: Cargar el arbol de Huffman a partir del buffer de una tabla de
;                  ́
;   códigos. El  ́arbol de Huffman se utilizará para facilitar el proceso de descompresion.
  
global cargar_arbol_huffman
extern calloc
extern printf
extern free

%define offset_simbolo 0
%define offset_apariciones 1
%define offset_valido 5
%define offset_p_padre	9 
%define offset_p_izq	13
%define offset_p_der	17

%define offset_codigo 0
%define offset_codigo_rev 4
%define offset_long_codigo 8
%define offset_codigo_t_valido 12	
	
%define valido 1
%define invalido 0
%define null 0
%define error 1
%define ok 0
%define max_cant_simbolos 256
%define sizeof_nodo_arbol 21

section .data
msg_memoria_insuficiente:	db	'ERROR: Memoria insuficiente',10,0
msg_error_tabla_cod_null:	db	'ERROR: El ptr a la tabla de codigos no puede ser null',10,0



%define p_tabla_codigos ebp+8
%define pp_arbol ebp+12

section .text
cargar_arbol_huffman:
	push ebp
	mov ebp,esp
	push ebx
	push esi
	push edi
	
	;;;mov dword pp_arbol, null
	
	mov esi, [p_tabla_codigos]
	cmp esi, null
	jne _p_tabla_codigos_ok
	
	push dword msg_error_tabla_cod_null
	call printf
	add esp,4
	
	mov eax, error
	jmp fin
	
_p_tabla_codigos_ok:	
	xor edi,edi	; edi es el contador del ciclo
	
	
	push dword sizeof_nodo_arbol
	push dword 1
	call calloc
	add esp,8
	
	mov ebx, [pp_arbol]
	mov [ebx], eax		; guardamos el puntero al arbol.
	mov ebx, eax		; ebx apunta al arbol

	mov dword [ebx+offset_valido], invalido	; creamos siempre el primer nodo invalido del arbol
						; en caso de tener:
						; 0 codigo => al final liberamos y ponemos el ptr en null
						; 1 codigo => al final subimos el nodo y destruimos el de la raiz.
	xor edx, edx 			; edx guardará la cantidad de codigos validos encontrados.
	
		
_ciclo:
	cmp edi, max_cant_simbolos
	jne _quedan_simbolos
	mov eax, ok
	jmp _pos_proceso
	
_quedan_simbolos:
	
	cmp dword [esi+offset_codigo_t_valido], valido
	je _agregar_al_arbol
	jmp _incremento		; si no es valido sigue con el siguiente codigo.	
	
_agregar_al_arbol:
	inc edx		; hay un simbolo más válido.
	mov ebx, [pp_arbol]
	mov ebx, [ebx]		; ebx apunta al arbol en si.
	
	mov eax, [esi+offset_codigo]
	mov ecx, 32
	sub ecx, [esi+offset_long_codigo]
	shl eax, cl				; dejamos el codigo en los bits mas sig.
	mov ecx, [esi+offset_long_codigo]  ; ecx contador del ciclo interno.
	
_ciclo_agregar:
	
	cmp ecx, 0
	jne _seguir_bajando
	mov dword [ebx+offset_valido], valido
	mov ecx, edi
	mov [ebx+offset_simbolo], cl
	jmp _incremento

_seguir_bajando:

	shl eax,1
	jc _hijo_derecho
	
_hijo_izquierdo:
	push eax		;   
	push edx		; Protegemos los registros no protegidos en conv. c
	push ecx		;	
	mov ecx, [ebx+offset_p_izq]
	mov eax, ecx		; lo copiamos por si ya existía y tenerlo en _ya_existe_izq
	cmp ecx, null
	jne _ya_existe_izq
	
	push dword sizeof_nodo_arbol
	push dword 1
	call calloc
	add esp,8
	
	mov [eax+offset_p_padre], ebx
	mov [ebx+offset_p_izq], eax

_ya_existe_izq:
	
	; mal no esta inicializado el eax
	mov ebx, eax		; ebx ahora apunta al nuevo arbol izquierdo
	
	pop ecx			;
	pop edx			; Recureramos registros.
	pop eax			;
		
	dec ecx			; resta un bit menos por procesar
	jmp _ciclo_agregar
	
_hijo_derecho:
	push eax		;   
	push edx		; Protegemos los registros no protegidos en conv. c
	push ecx		;
	
	mov ecx, [ebx+offset_p_der]
	mov eax, ecx		; lo copiamos en eax para utilizarlo en _ya_existe_der
	cmp ecx, null
	jne _ya_existe_der

	push dword sizeof_nodo_arbol
	push dword 1
	call calloc
	add esp,8
	
	mov [eax+offset_p_padre], ebx
	mov [ebx+offset_p_der], eax
	
_ya_existe_der:
	mov ebx, eax		; esi ahora apunta al nuevo arbol derecho
	
	pop ecx			;
	pop edx			; Recureramos registros.
	pop eax			;
	
	dec ecx			; resta un bit menos por procesar
	jmp _ciclo_agregar	


_incremento:

	add esi,16
	inc edi
	jmp _ciclo
	
_pos_proceso:
	; aquí si edx que guarda en nro. de codigos validos.
	; edx = 0 => liberamos el nodo principal y ponemos a null el ptr al arbol
	; edx = 1 => subimos el nodo principal y liberamos el nodo que antes era raiz.
	; edx > 1 => no hacemos nada, ya quedo el arbol correcto.

	cmp edx, 0
	jne _ver_si_solo_hay_un_codigo
	; si no hay codigos, entonces debemos liberar el nodo creado al principio.
	
	mov esi, [pp_arbol] 	; esi tiene el puntero doble
	mov ebx, [esi]		; ebx apunta al primer nodo del arbol
	push ebx
	call free
	add esp,4
	
	mov dword [esi], null		; el arbol es nulo
	
_ver_si_solo_hay_un_codigo:
	cmp edx, 1
	jne fin
	; si hay un solo codigo subimos el arbol y dejamos solo un nodo.
	
	mov esi, [pp_arbol]	; esi tiene el puntero doble
	mov ebx, [esi]		; ebx apunta al primer nodo del arbol

	mov edi, [ebx+offset_p_izq]	; edi apunta al hijo izq
	cmp edi, null
	je _subir_derecho
		
_subir_izquierdo:
	mov [esi], edi
	mov dword [edi+offset_p_padre], null
	jmp _liberar_nodo_extra

_subir_derecho:
	mov edi, [ebx+offset_p_der]
	mov [esi], edi
	mov dword [edi+offset_p_padre], null
	
_liberar_nodo_extra:
	push ebx
	call free
	add esp,4
	
fin:	
	
	pop edi
	pop esi
	pop ebx
	leave
	ret
